/*
 * Copyright (c) 2009 Red Hat, Inc.
 * -------------------------------------
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Apache License v2.0 which accompanies this distribution.
 *
 *     The Eclipse Public License is available at
 *     http://www.eclipse.org/legal/epl-v10.html
 *
 *     The Apache License v2.0 is available at
 *     http://www.opensource.org/licenses/apache2.0.php
 *
 * You may elect to redistribute this code under either of these licenses.
 */

package org.lealone.common.logging;

import static org.slf4j.spi.LocationAwareLogger.DEBUG_INT;
import static org.slf4j.spi.LocationAwareLogger.ERROR_INT;
import static org.slf4j.spi.LocationAwareLogger.INFO_INT;
import static org.slf4j.spi.LocationAwareLogger.TRACE_INT;
import static org.slf4j.spi.LocationAwareLogger.WARN_INT;

import org.lealone.common.logging.spi.LogDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.spi.LocationAwareLogger;

/**
 * @author <a href="http://tfox.org">Tim Fox</a>
 */
public class SLF4JLogDelegate implements LogDelegate {

    private static final String FQCN = org.lealone.common.logging.Logger.class.getCanonicalName();

    private final Logger logger;

    SLF4JLogDelegate(final String name) {
        logger = LoggerFactory.getLogger(name);
    }

    @Override
    public boolean isInfoEnabled() {
        return logger.isInfoEnabled();
    }

    @Override
    public boolean isDebugEnabled() {
        return logger.isDebugEnabled();
    }

    @Override
    public boolean isTraceEnabled() {
        return logger.isTraceEnabled();
    }

    @Override
    public void fatal(final Object message) {
        log(ERROR_INT, message);
    }

    @Override
    public void fatal(final Object message, final Throwable t) {
        log(ERROR_INT, message, t);
    }

    @Override
    public void error(final Object message) {
        log(ERROR_INT, message);
    }

    @Override
    public void error(Object message, Object... params) {
        log(ERROR_INT, message, null, params);
    }

    @Override
    public void error(final Object message, final Throwable t) {
        log(ERROR_INT, message, t);
    }

    @Override
    public void error(Object message, Throwable t, Object... params) {
        log(ERROR_INT, message, t, params);
    }

    @Override
    public void warn(final Object message) {
        log(WARN_INT, message);
    }

    @Override
    public void warn(Object message, Object... params) {
        log(WARN_INT, message, null, params);
    }

    @Override
    public void warn(final Object message, final Throwable t) {
        log(WARN_INT, message, t);
    }

    @Override
    public void warn(Object message, Throwable t, Object... params) {
        log(WARN_INT, message, t, params);
    }

    @Override
    public void info(final Object message) {
        log(INFO_INT, message);
    }

    @Override
    public void info(Object message, Object... params) {
        log(INFO_INT, message, null, params);
    }

    @Override
    public void info(final Object message, final Throwable t) {
        log(INFO_INT, message, t);
    }

    @Override
    public void info(Object message, Throwable t, Object... params) {
        log(INFO_INT, message, t, params);
    }

    @Override
    public void debug(final Object message) {
        log(DEBUG_INT, message);
    }

    @Override
    public void debug(final Object message, final Object... params) {
        log(DEBUG_INT, message, null, params);
    }

    @Override
    public void debug(final Object message, final Throwable t) {
        log(DEBUG_INT, message, t);
    }

    @Override
    public void debug(final Object message, final Throwable t, final Object... params) {
        log(DEBUG_INT, message, t, params);
    }

    @Override
    public void trace(final Object message) {
        log(TRACE_INT, message);
    }

    @Override
    public void trace(Object message, Object... params) {
        log(TRACE_INT, message, null, params);
    }

    @Override
    public void trace(final Object message, final Throwable t) {
        log(TRACE_INT, message, t);
    }

    @Override
    public void trace(Object message, Throwable t, Object... params) {
        log(TRACE_INT, message, t, params);
    }

    private void log(int level, Object message) {
        log(level, message, null);
    }

    private void log(int level, Object message, Throwable t) {
        log(level, message, t, (Object[]) null);
    }

    private void log(int level, Object message, Throwable t, Object... params) {
        String msg = (message == null) ? "NULL" : message.toString();

        // We need to compute the right parameters.
        // If we have both parameters and an error, we need to build a new array [params, t]
        // If we don't have parameters, we need to build a new array [t]
        // If we don't have error, it's just params.
        Object[] parameters = params;
        if (params != null && t != null) {
            parameters = new Object[params.length + 1];
            System.arraycopy(params, 0, parameters, 0, params.length);
            parameters[params.length] = t;
        } else if (params == null && t != null) {
            parameters = new Object[] { t };
        }

        if (logger instanceof LocationAwareLogger) {
            LocationAwareLogger l = (LocationAwareLogger) logger;
            l.log(null, FQCN, level, msg, parameters, t);
        } else {
            switch (level) {
            case TRACE_INT:
                logger.trace(msg, parameters);
                break;
            case DEBUG_INT:
                logger.debug(msg, parameters);
                break;
            case INFO_INT:
                logger.info(msg, parameters);
                break;
            case WARN_INT:
                logger.warn(msg, parameters);
                break;
            case ERROR_INT:
                logger.error(msg, parameters);
                break;
            default:
                throw new IllegalArgumentException("Unknown log level " + level);
            }
        }
    }
}
